package org.eclipse.epsilon.emc.rdbms.core.unitesting.blackbox;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;

import org.eclipse.epsilon.emc.rdbms.core.imodel.DBReflexiveModel;
import org.eclipse.epsilon.emc.rdbms.core.imodel.DBReflexiveModelElement;
import org.eclipse.epsilon.emc.rdbms.core.persistancemechanism.H2Database;
import org.eclipse.epsilon.emc.rdbms.core.persistancemechanism.RelationalDatabase;
import org.eclipse.epsilon.emc.rdbms.core.persistanceobject.PersistanceObject;
import org.eclipse.epsilon.eol.exceptions.EolRuntimeException;
import org.eclipse.epsilon.eol.exceptions.models.EolModelElementTypeNotFoundException;
import org.eclipse.epsilon.eol.exceptions.models.EolNotInstantiableModelElementTypeException;
import org.junit.Before;
import org.junit.Test;


public class JUnit_BlackBox_PersistanceObject 
{
	RelationalDatabase Connection = new H2Database("jdbc:h2:","..//org.eclipse.epsilon.emc.rdbms//sample_db//h2","epsilon");
	DBReflexiveModel rModel = new DBReflexiveModel();  //Create a new model.
	PersistanceObject PersistanceObject = new PersistanceObject();
	
	@Before 
	public void PersistanceObject_pre_test ()
	{
	Connection.db_setup("C:\\config.sql");	
	rModel.setName("epsilon"); //Set the Model Name
	}

	
	@Test
	public void PersistanceObject_testUpdateElement() 
	{
	try 
	{
		Object element = rModel.createInstance("CUSTOMER");
		HashMap<String, Object> properties = new HashMap<String, Object>();
		properties.put("firstName", "UpdatedForeName");
		properties.get("firstName");
		assertEquals("This should return the Updated Forename","",rModel.getPropertyGetter().invoke(element, "firstName"));
		PersistanceObject.updateElement(((DBReflexiveModelElement) element), properties);
	    assertEquals("This should return the Updated Forename","UpdatedForeName",rModel.getPropertyGetter().invoke(element, "firstName"));
	} 
	catch (SQLException e) 
	{
		fail("SQL Exception");
		e.printStackTrace();
	} 
	catch (EolModelElementTypeNotFoundException e) 
	{
		fail("EOL Element Type Not Found Exception");
		// TODO Auto-generated catch block
		e.printStackTrace();
	} 
	catch (EolNotInstantiableModelElementTypeException e)
	{
		fail("Element Type not Instantiable");
		// TODO Auto-generated catch block
		e.printStackTrace();
	} 
	catch (EolRuntimeException e) 
	{
		fail("EolRuntimeException error has occured");
		// TODO Auto-generated catch block
		e.printStackTrace();
	}	
	}
		
	@Test
	public void PersistanceObject_testUpdateElementNullColumn() 
	{
	try 
	{
		Object element = rModel.createInstance("CUSTOMER");
		HashMap<String, Object> properties = new HashMap<String, Object>();
		properties.put("FORENAME", "UpdatedForeName");
		assertEquals("This should return the Updated Forename",null,rModel.getPropertyGetter().invoke(element, null));
		PersistanceObject.updateElement(((DBReflexiveModelElement) element), properties);
	    assertEquals("This should return the Updated Forename",null,rModel.getPropertyGetter().invoke(element, null));
	} 
	catch (SQLException e) 
	{
		fail("SQL Exception");
		e.printStackTrace();
	} 
	catch (EolModelElementTypeNotFoundException e) 
	{
		fail("EOL Element Type Not Found Exception");
		// TODO Auto-generated catch block
		e.printStackTrace();
	} 
	catch (EolNotInstantiableModelElementTypeException e)
	{
		fail("Element Type not Instantiable");
		// TODO Auto-generated catch block
		e.printStackTrace();
	} 
	catch (EolRuntimeException e) 
	{
		fail("EolRuntimeException error has occured");
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	}
	
	@Test
	public void PersistanceObject_testUpdateElementNullElement() 
	{
	try 
	{
		Object element = rModel.createInstance("CUSTOMER");
		HashMap<String, Object> properties = new HashMap<String, Object>();
		properties.put("FORENAME", "UpdatedForeName");
		assertEquals("This should return the Updated Forename",null,rModel.getPropertyGetter().invoke(null, "FORENAME"));
		PersistanceObject.updateElement(((DBReflexiveModelElement) element), properties);
	    assertEquals("This should return the Updated Forename",null,rModel.getPropertyGetter().invoke(null, "FORENAME"));
	    fail("This should throw a null pointer Exception");
	} 
	catch (SQLException e) 
	{
		fail("SQL Exception");
		e.printStackTrace();
	} 
	catch (EolModelElementTypeNotFoundException e) 
	{
		fail("EOL Element Type Not Found Exception");
		// TODO Auto-generated catch block
		e.printStackTrace();
	} 
	catch (EolNotInstantiableModelElementTypeException e)
	{
		fail("Element Type not Instantiable");
		// TODO Auto-generated catch block
		e.printStackTrace();
	} 
	catch (EolRuntimeException e) 
	{
		fail("EolRuntimeException error has occured");
		// TODO Auto-generated catch block
		e.printStackTrace();
	}	
	catch (NullPointerException e) 
	{
		// TODO Auto-generated catch block
		e.printStackTrace();
	}		
	}

	
	@Test
	public void PersistanceObject_testDeleteElement() 
	{
			Object element;
			try {
				element = rModel.createInstance("CUSTOMER");
				ArrayList<String> properties = new ArrayList<String>();
				ResultSet resultset = PersistanceObject.getElement((DBReflexiveModelElement) element, properties);
				resultset.last();
				assertEquals("Should be 4 records in the element table",1,resultset.getRow());
				PersistanceObject.deleteElement((DBReflexiveModelElement) element);
				resultset = PersistanceObject.getElement((DBReflexiveModelElement) element, properties);
				resultset.last();
			    assertEquals("This should return the Updated Forename",0,resultset.getRow());
			} 
			catch (EolModelElementTypeNotFoundException e) {
				fail("Eol Model Type Not Found error has occured");
				e.printStackTrace();
			} 
			catch (EolNotInstantiableModelElementTypeException e) {
				fail("EOL Not instantialble Model Element Type");
				e.printStackTrace();
			} catch (SQLException e) 
			{
				fail("An SQL Exception has been thrown");
				e.printStackTrace();
			} 
			catch (EolRuntimeException e) 
			{
				fail("EolRuntimeException error has occured");
				e.printStackTrace();
			}	
	}
	
	
	@Test
	public void PersistanceObject_testDeleteElement_nullElement() 
	{
			Object element;
			try {
				element = rModel.createInstance(null);
				ArrayList<String> properties = new ArrayList<String>();
				ResultSet resultset = PersistanceObject.getElement((DBReflexiveModelElement) element, properties);
				resultset.last();
				assertEquals("Should be 4 records in the element table",1,resultset.getRow());
				PersistanceObject.deleteElement(null);
				resultset = PersistanceObject.getElement((DBReflexiveModelElement) element, properties);
				resultset.last();
			    assertEquals("This should return the Updated Forename",0,resultset.getRow());
			} 
			catch (EolModelElementTypeNotFoundException e) {
				fail("Eol Model Type Not Found error has occured");
				e.printStackTrace();
			} 
			catch (EolNotInstantiableModelElementTypeException e) {
				fail("EOL Not instantialble Model Element Type");
				e.printStackTrace();
			} catch (SQLException e) 
			{
				fail("An SQL Exception has been thrown");
				e.printStackTrace();
			} 
			catch (EolRuntimeException e) 
			{
				fail("EolRuntimeException error has occured");
				e.printStackTrace();
			}
			catch (NullPointerException e) 
			{
				//Null Pointer Exception has occured.
				e.printStackTrace();
			}
	}
	
	
	@Test
	public void testGetElement() 
	{	
	try 
	{
		Object customerID = null;
		DBReflexiveModelElement element = PersistanceObject.addNewElement(new DBReflexiveModelElement("CUSTOMER"), new HashMap<String, Object>());	
		ResultSet elementlist = PersistanceObject.getElement(element, new ArrayList<String>());		
		while(elementlist.next())
		{
			customerID = elementlist.getString(1);
		}
		assertEquals("Check customerID","4",customerID);
		
	} 
	catch (SQLException e) 
	{
		fail("SQL Exception has occured");
		// TODO Auto-generated catch block
		e.printStackTrace();
	}	
	}
	

	@Test
	public void testGetElement_nullelement() 
	{	
	try 
	{
		Object customerID = null;
		DBReflexiveModelElement element = PersistanceObject.addNewElement(new DBReflexiveModelElement("CUSTOMER"), new HashMap<String, Object>());
		ResultSet elementlist = PersistanceObject.getElement(element, null);		
		while(elementlist.next())
		{
			customerID = elementlist.getString(1);
		}
	} 
	catch (SQLException e) 
	{
		fail("SQL Exception has occured");
		// TODO Auto-generated catch block
		e.printStackTrace();
	}	
	catch (NullPointerException e)
	{
	//This should throw an exception here.
	}
}

	@Test
	public void testGetElement_nullArrayList() 
	{	
	try 
	{
		Object customerID = null;
		DBReflexiveModelElement element = null;
		ResultSet elementlist = PersistanceObject.getElement(element, new ArrayList<String>());		
		while(elementlist.next())
		{
			customerID = elementlist.getString(1);
		}
		
		fail("this should throw a null pointer Exception");
	} 
	catch (SQLException e) 
	{
		fail("SQL Exception has occured");
		// TODO Auto-generated catch block
		e.printStackTrace();
	}	
	catch (NullPointerException e)
	{
	//This should throw an exception here.
	}
}


	@Test
	public void testGetElement_PopulatedArrayList() 
	{	
	try 
	{
		Object customerID = null;
		DBReflexiveModelElement element = PersistanceObject.addNewElement(new DBReflexiveModelElement("CUSTOMER"), new HashMap<String, Object>());
		ArrayList<String> properties =  new ArrayList<String>();
		properties.add("CUSTOMERID");
		ResultSet elementlist = PersistanceObject.getElement(element,properties);		
		while(elementlist.next())
		{
			customerID = elementlist.getString(1);
		}
		assertEquals("This should return the customerID","4",customerID);	
	} 
	catch (SQLException e) 
	{
		fail("SQL Exception has occured");
		// TODO Auto-generated catch block
		e.printStackTrace();
	}	
	catch (NullPointerException e)
	{
	//This should throw an exception here.
	}
}
	

	@Test
	public void PersistanceObject_testAddNewElement() 
	{
		Object customerID = null;
		try 
		{
			DBReflexiveModelElement element = PersistanceObject.addNewElement(new DBReflexiveModelElement("CUSTOMER"), new HashMap<String, Object>());
		} 
		catch (SQLException e) 
		{
		fail("This should not throw an exception");
			e.printStackTrace();
		}
	}

	@Test
	public void PersistanceObject_testAddNewElementNullelement() 
	{
		Object customerID = null;
		try 
		{
			DBReflexiveModelElement element = PersistanceObject.addNewElement(null, new HashMap<String, Object>());
		fail("This should throw a Null Pointer Exception");
		} 
		catch (SQLException e) 
		{
		fail("This should not throw an exception");
			e.printStackTrace();
		}
		catch (NullPointerException e) 
		{
			e.printStackTrace();
		}
	}
	
	
	@Test
	public void PersistanceObject_testAddNewElementNullHashMap() 
	{
		Object customerID = null;
		try 
		{
			DBReflexiveModelElement element = PersistanceObject.addNewElement(new DBReflexiveModelElement("CUSTOMER"), null);
			ArrayList<String> properties =  new ArrayList<String>();
			properties.add("CUSTOMERID");
			ResultSet elementlist = PersistanceObject.getElement(element,properties);		
			while(elementlist.next())
			{
				customerID = elementlist.getString(1);
			}
			assertEquals("This should return the customerID","5",customerID);	
		} 
		catch (SQLException e) 
		{
		fail("This should not throw an exception");
			e.printStackTrace();
		}
		catch (NullPointerException e) 
		{
	    }
	}
	
	@Test
	public void testGetKeys() 
	{
		ResultSet keys = PersistanceObject.getKeys("CUSTOMER");
		try 
		{
			keys.last();
			assertEquals("Should have a key count of 1",1,keys.getRow());
			assertEquals("Key should be customerID","CUSTOMERID",keys.getString(4));
		} 
		catch (SQLException e) 
		{
	     	fail("should not throw an SQL Exception here");
			e.printStackTrace();
		}
	}
	
	@Test
	public void testGetKeys_TableWithNoKeys() 
	{
		ResultSet keys = PersistanceObject.getKeys("ORDER_ITEM");
		try 
		{
			//keys.last();
			assertEquals("Should have a key count of 0",0,keys.getRow());
		} 
		catch (SQLException e) 
		{
	     	fail("should not throw an SQL Exception here");
			e.printStackTrace();
		}
	}
	
	@Test
	public void testGetKeys_TableNotExistsing() 
	{
		ResultSet keys = PersistanceObject.getKeys("dshgdvsd");
		try 
		{
			//keys.last();
			assertEquals("Should have a key count of 0",0,keys.getRow());
		} 
		catch (SQLException e) 
		{
	     	fail("should not throw an SQL Exception here");
			e.printStackTrace();
		}
	}
	
	@Test
	public void testGetKeys_TableNull() 
	{
		ResultSet keys = PersistanceObject.getKeys(null);
		try 
		{
			//keys.last();
			assertEquals("Should have a key count of 0",0,keys.getRow());
		} 
		catch (SQLException e) 
		{
	     	fail("should not throw an SQL Exception here");
			e.printStackTrace();
		}
	}
	
	@Test
	public void testGetAllOfType() 
	{
	PersistanceObject PersistanceObject   = new PersistanceObject();
	String type = new String();
	ArrayList<String> columns = new ArrayList<String>();
	HashMap<String, Object> criteria = new HashMap<String, Object>();
	type = "CUSTOMER";
	try 
	{
		ResultSet result = PersistanceObject.getAllOfType(type, columns, criteria);
	    result.last();    
	    assertEquals("There should be 3 rows returned",3,result.getRow()); 
	} 
	catch (SQLException e) 
	{
		fail("should not throw a SQL Exception");
		e.printStackTrace();
	}
	}

	@Test
	public void testGetAllOfType_TableDoesNotExists() 
	{
	PersistanceObject PersistanceObject   = new PersistanceObject();
	String type = new String();
	ArrayList<String> columns = new ArrayList<String>();
	HashMap<String, Object> criteria = new HashMap<String, Object>();
	type = "dskdhdshd";
	try 
	{
		ResultSet result = PersistanceObject.getAllOfType(type, columns, criteria);
	    result.last();    
	    assertEquals("There should be 0 rows returned",0,result.getRow()); 
	} 
	catch (SQLException e) 
	{
		e.printStackTrace();
	}
	}
	
	@Test
	public void testGetAllOfType_TableIsNull() 
	{
	PersistanceObject PersistanceObject   = new PersistanceObject();
	String type = new String();
	ArrayList<String> columns = new ArrayList<String>();
	HashMap<String, Object> criteria = new HashMap<String, Object>();
	type = null;
	try 
	{
		ResultSet result = PersistanceObject.getAllOfType(type, columns, criteria);
	    result.last();    
	    assertEquals("There should be 0 rows returned",0,result.getRow()); 
	} 
	catch (SQLException e) 
	{
			e.printStackTrace();
	}
	}
}
